﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace ConsoleAppDemo {
    public class InterlockManage {
        private static int usingResource = 0;
        private const int numThreadIterations = 5;
        public static void MyThreadProc()
        {
            for (int i = 0; i < numThreadIterations; i++)
            {
                UseResource();
                Thread.Sleep(1000);
            }
        }
        private static bool UseResource()
        {
            if (0 == Interlocked.Exchange(ref usingResource, 1))
            {
                Console.WriteLine("{0} acquired the lock", Thread.CurrentThread.Name);
                Thread.Sleep(500);
                Console.WriteLine("{0} exiting lock", Thread.CurrentThread.Name);
                Interlocked.Exchange(ref usingResource, 0);
                return true;
            }
            else
            {
                Console.WriteLine("   {0} was denied the lock", Thread.CurrentThread.Name);
                return false;
            }
        }
    }

    public class InterIncAndDec {
        private static int threadCount = 0;
        private static Random rnd = new Random();
        public static void RndThreadFunc()
        {
            Interlocked.Increment(ref threadCount);
            try
            {
                int sleepTime = rnd.Next(1000, 12000);
                Thread.Sleep(sleepTime);
            }
            finally
            {
                Interlocked.Decrement(ref threadCount);
            }
        }
        public static void RptThread()
        {
            while (true)
            {
                int threadNumber = 0;
                threadNumber = Interlocked.Exchange(ref threadCount, threadCount);
                Console.WriteLine("{0} Thread(s) alive", threadNumber);
                Thread.Sleep(1000);
            }
        }
    }
    /// <summary>
    /// 一个类似于自旋锁的类，也类似于对共享资源的访问机制
    /// 如果资源已被占有，则等待一段时间再尝试访问，
    /// 如此循环，直到能够获得资源的使用权为止
    /// </summary>
    public class SpinLock {
        /// <summary>
        /// 资源状态锁，0--未被占有，1--已被占有
        /// </summary>
        private int theLock = 0;
        /// <summary>
        /// 等待时间
        /// </summary>
        private int spinWait;
        public SpinLock(int spinWait)
        {
            this.spinWait = spinWait;
        }
        /// <summary>
        /// 访问
        /// </summary>
        public void Enter()
        {
            //如果已被占有，则继续等待
            while (Interlocked.CompareExchange(ref theLock, 1, 0) == 1)
            {
                Thread.Sleep(spinWait);
            }
        }
        /// <summary>
        /// 退出
        /// </summary>
        public void Exit()
        {
            //重置资源锁
            Interlocked.Exchange(ref theLock, 0);
        }
    }

    public class SpinLockManager : IDisposable {
        private SpinLock spinLock;
        public SpinLockManager(SpinLock spinLock)
        {
            this.spinLock = spinLock;
            spinLock.Enter();
        }
        /// <summary>
        /// 任务结束后，执行Dispose()方法
        /// </summary>
        public void Dispose()
        {
            spinLock.Exit();
        }
    }

    public class SpinLockProvider {
        private static Random rnd = new Random();
        //创建资源锁，管理资源的访问。
        private static SpinLock logLock = new SpinLock(10);
        //以写的方式打开文件，选择追加模式
        private static StreamWriter fsLog =
            new StreamWriter(File.Open("Log.txt",
                FileMode.Append,
                FileAccess.Write,
                FileShare.None));
        public static void RndThreadFunc()
        {
            using (new SpinLockManager(logLock))
            {
                fsLog.WriteLine("Thread Starting");
                fsLog.Flush();
            }
            int time = rnd.Next(10, 200);
            Thread.Sleep(time);
            using (new SpinLockManager(logLock))
            {
                fsLog.WriteLine("Thread Exiting");
                fsLog.Flush();
            }
        }
    }
}
